<?php

/**
 * author: Shenzhongchao
 * createTime: 2019/12/27
 *
 */

class Tickets
{
    public $fromStation = null;
    public $toStation = null;
    public $date = null;

    public function __construct($fromStation = null, $toStation = null, $date = null)
    {
        if (!file_exists(ROOT_PATH . '/sites_data/station.json')) {
            $this->parseStation();
        }

        $this->fromStation = $fromStation;
        $this->toStation = $toStation;
        $this->date = $date;
    }

    /**
     * 入口函数
     */
    public function run()
    {
        if (is_null($this->fromStation) || is_null($this->toStation))
            throw new Exception('起始站不能为空!');
        is_null($this->date) && $date = date('Y-m-d');
        //$url = 'https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date='.$this->date.'&leftTicketDTO.from_station='.$this->fromStation.'&leftTicketDTO.to_station='.$this->toStation.'&purpose_codes=ADULT';
        //$url = 'https://kyfw.12306.cn/otn/lcxxcx/query?purpose_codes=ADULT&queryDate=' . $this->date . '&from_station=';
        //$url .= $this->fromStation . '&to_station=' . $this->toStation;
        $url = 'https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date='.$this->date.'&leftTicketDTO.from_station='.$this->fromStation.'&leftTicketDTO.to_station='.$this->toStation.'&purpose_codes=ADULT';
        //var_dump($url);
        $ticketInfo = $this->curlGet($url);

        return $ticketInfo;
    }

    /**
     * 解析火车站信息
     */
    private function parseStation()
    {
        $url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8992';
        $station = $this->curlGet($url, false);

        if (empty($station)) {
            throw new Exception('获取站点信息失败！');
        }

        $delStr = "var station_names ='"; //需要截断的字符
        $station = substr($station, strlen($delStr), strlen($station));

        $station = explode('@', $station);
        $json = [
            'message' => ''
        ];

        foreach ($station as $key => $vo) {
            if (empty($vo)) continue;

            $st = explode('|', $vo);
            $json['value'][] = [
                'stationName' => $st['1'],
                'shortName' => $st['3'],
                'stationFlag' => $st['2']
            ];
        }
        unset($station);

        file_put_contents(ROOT_PATH . '/sites_data/station.json', json_encode($json));
    }

    /**
     * 采集数据
     * @param $url
     * @param $decode
     */
    private function curlGet($url, $decode = true)
    {
        $ch = curl_init();
        $timeout = 5;
        // 12306官网余票查询后的 Request Headers
        $headers = array(
            'Accept:*/*',
            'Accept-Encoding:gzip, deflate, br',
            'Accept-Language:zh-CN,zh;q=0.9',
            'Cache-Control:no-cache',
            'Connection:keep-alive',
            'Cookie:JSESSIONID=2D7B808DDC0075DE3ECDD5FF287C92DA; route=6f50b51faa11b987e576cdb301e545c4; RAIL_EXPIRATION=1577725265219; RAIL_DEVICEID=DOhuAZAGUcj3lz0C3zeuU4u_SnCpLptLPYuDbsN9v0LL5DDbq36OsVKy5gVvIhhCZj2xZqcw1Qyr8DPN4EAxlmQJpwGPXaQbeyVUuEygtRuV2WkRlF_K_6nsVn3lStbJZqGPITzro0bNGp8aSLZgCLVz_imlrTU0; BIGipServerpool_passport=183304714.50215.0000; _jc_save_wfdc_flag=dc; _jc_save_fromDate=2020-01-13; ten_key=aG9RY1ZjHe4agE+ZjQpPXOdlbzhFeo9z; ten_js_key=aG9RY1ZjHe4agE%2BZjQpPXOdlbzhFeo9z; ten_join_key=aG9RY1ZjHe4agE%2BZjQpPXOdlbzhFeo9z%2CaG9RY1ZjHe4agE%2BZjQpPXOdlbzhFeo9z; _jc_save_toStation=%u6842%u6797%2CGLZ; _jc_save_fromStation=%u5E7F%u5DDE%u5357%2CIZQ; BIGipServerotn=2162688266.64545.0000; _jc_save_toDate=2019-12-28',
            'Host:kyfw.12306.cn',
            'If-Modified-Since:0',
            'Referer:https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc',
            'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36',
            'X-Requested-With:XMLHttpRequest',
        );

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  //将 curl_exec() 获取的信息以文件流的形式返回，而不是直接输出。
        curl_setopt($ch, CURLOPT_ENCODING, "gzip"); //指定gzip压缩
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);  // 从证书中检查SSL加密算法是否存在
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        $result = curl_exec($ch);   //抓取内容文件流并传给 $result
        curl_close($ch);

        //将JSON数据转换为PHP变量(数组或对象)
        $decode && $result = json_decode($result, true);
        //var_dump($result);
  
        //真正用到的数据，如车次，日期等。每一条数据代表一条余票数据都是用 | 连结，需要分割重整
        //var_dump($result['data']['result']);   
        //var_dump(count($result['data']['result']));   //余票数据数量
        
        if ($result['data']['result'] != null) {
            $result['data']['result'] = $this->replace($result['data']['result']);
        }else{
            throw new Exception('站点信息为空！');
        }

        //var_dump( $result['data']['result']);
        return $result;
    }

    /**
     * 替换数据
     * 1. 将每一条余票数据都进行分割，每一条都是一维索引数组形式，
     *    但最终只需其中部分元素的值且最终要通过特定键名取值，需要替换成一维关联数组
     * 2. 余票数据变成关联数组后，如果其中的某些元素的值为""，需要换成"--"，也可以在前端显示再替换
     * @param $data
     * @param $decode
     * 
     *-----------------------------------------------------------------------------
     * 余票数据一维索引数组转成一维关联数组
     * $tempArr[2]  => 车编号，如 "6c000D186205"
     * $tempArr[3]  => 车次，如 "D2804"
     * $tempArr[6]  => 出发站
     * $tempArr[7]  => 到达站
     * $tempArr[8]  => 出发时间
     * $tempArr[9]  => 到达时间
     * $tempArr[13] => 日期
     * $tempArr[10] => 历时，如 “02:36”
     * $tempArr[32] => 商务座特等座 数字或有或无或候补
     * $tempArr[31] => 一等座 数字或有或无或候补
     * $tempArr[30] => 二等座 数字或有或无或候补 
     * $tempArr[21] => 高级软卧           
     * $tempArr[23] => 软卧一等卧  
     * $tempArr[33] => 动卧       
     * $tempArr[28] => 硬卧二等卧
     * $tempArr[27] => 软座      目前解析不出来是哪一项，暂用27       
     * $tempArr[29] => 硬座 
     * $tempArr[26] => 无座 数字或有或无
     * $tempArr[26] => 其他      目前解析不出来是哪一项，暂用46
     * $tempArr[1]  => 备注 “预订”
     ------------------------------------------------------------------------------*/
    private function replace($data){
        //存放所需部分元素的一维关联数组，最终页面利用键名显示数据，所以需要替换进去 $result['data']['result']
        $speArr = [];
        foreach ($data as $key => $val) {
            //将每一条余票数据都进行分割，每一条都是一维索引数组形式，但最终只需其中部分元素的值
            $tempArr = explode('|', $val); // 如 $tempArr = explode('|', $result['data']['result'][0]);
            //取出每一条余票数据中所需的部分特定元素
            $speArr['station_train_code']  = ($tempArr[2] !== '')  ? $tempArr[2]  : '--';  // 车编号
            $speArr['station_train_no']    = ($tempArr[3] !== '')  ? $tempArr[3]  : '--';  // 车次，如 "D2804"
            $speArr['start_station']       = ($tempArr[6] !== '')  ? $tempArr[6]  : '--';  // 出发站
            $speArr['end_station']         = ($tempArr[7] !== '')  ? $tempArr[7]  : '--';  // 到达站
            $speArr['start_time']          = ($tempArr[8] !== '')  ? $tempArr[8]  : '--';  // 出发时间
            $speArr['end_time']            = ($tempArr[9] !== '')  ? $tempArr[9]  : '--';  // 到达时间
            $speArr['date']                = ($tempArr[13] !== '') ? $tempArr[13] : '--'; // 日期
            $speArr['spend_time']          = ($tempArr[10] !== '') ? $tempArr[10] : '--'; // 历时，如 “02:36”
            $speArr['swztz_num']           = ($tempArr[32] !== '') ? $tempArr[32] : '--';  // 商务座特等座 数字或有或无或候补
            $speArr['yd_num']              = ($tempArr[31] !== '') ? $tempArr[31] : '--';  // 一等座 数字或有或无或候补
            $speArr['ed_num']              = ($tempArr[30] !== '') ? $tempArr[30] : '--';  // 二等座 数字或有或无或候补 
            $speArr['gr_num']              = ($tempArr[21] !== '') ? $tempArr[21] : '--';  // 高级软卧           
            $speArr['rw_num']              = ($tempArr[23] !== '') ? $tempArr[23] : '--';  // 软卧一等卧  
            $speArr['dw_num']              = ($tempArr[33] !== '') ? $tempArr[33] : '--';  // 动卧       
            $speArr['yw_num']              = ($tempArr[28] !== '') ? $tempArr[28] : '--';  // 硬卧二等卧
            $speArr['rz_num']              = ($tempArr[27] !== '') ? $tempArr[27] : '--';  // 软座      目前解析不出是哪项，暂用27       
            $speArr['yz_num']              = ($tempArr[29] !== '') ? $tempArr[29] : '--';  // 硬座 
            $speArr['wz_num']              = ($tempArr[26] !== '') ? $tempArr[26] : '--';  // 无座 数字或有或无
            $speArr['qt_num']              = ($tempArr[26] !== '') ? $tempArr[26] : '--';  // 其他      目前解析不出是12306哪项，暂用46
            $speArr['bz_num']              = ($tempArr[1]  !== '') ?$tempArr[1] : '--';    // 备注 “预订”
                
            //替换回去，原本为字符串的每一条数据，使用一维关联数组替换
            $data[$key] = $speArr;
        }
        return $data;
    }
}

  